~ chicken-core (chicken-5) /manual/Module (chicken condition)


  1[[tags: manual]]
  2[[toc:]]
  3
  4== Module (chicken condition)
  5
  6This module provides various procedures and special forms for raising
  7and handling exceptions with "condition objects".  Condition objects
  8provide a structured and composable way to encode the kind of
  9exception that took place, and provide the necessary context.
 10
 11CHICKEN's exception handling is based on the
 12[[http://srfi.schemers.org/srfi-12/srfi-12.html|SRFI-12]] exception
 13system.  This document contains the core of the SRFI-12 spec as well
 14as CHICKEN implementation specifics.
 15
 16There is also a {{srfi-12}} or {{(srfi 12)}} module which only
 17includes the standard procedures and macros from the SRFI document,
 18without the CHICKEN extensions.  {{(chicken condition)}} offers the
 19complete set of procedures and macros, both CHICKEN-specific and
 20standard SRFI-12.
 21
 22
 23== CHICKEN implementation
 24
 25=== System conditions
 26
 27All error-conditions signaled by the system are of kind {{exn}}.
 28The following composite conditions are additionally defined:
 29
 30<table>
 31
 32<tr><td> (exn arity) </td><td>
 33
 34Signaled when a procedure is called with the wrong number of arguments.
 35
 36</td></tr><tr><td> (exn type) </td><td>
 37
 38Signaled on type-mismatch errors, for example when an argument of the wrong
 39type is passed to a built-in procedure.
 40
 41</td></tr><tr><td> (exn arithmetic) </td><td>
 42
 43Signaled on arithmetic errors, like division by zero.
 44
 45</td></tr><tr><td> (exn i/o) </td><td>
 46
 47Signaled on input/output errors.
 48
 49</td></tr><tr><td> (exn i/o file) </td><td>
 50
 51Signaled on file-related errors.
 52
 53</td></tr><tr><td> (exn i/o net) </td><td>
 54
 55Signaled on network errors.
 56
 57</td></tr><tr><td> (exn bounds) </td><td>
 58
 59Signaled on errors caused by accessing non-existent elements of a collection.
 60
 61</td></tr><tr><td> (exn runtime) </td><td>
 62
 63Signaled on low-level runtime-system error-situations.
 64
 65</td></tr><tr><td> (exn runtime limit) </td><td>
 66
 67Signaled when an internal limit is exceeded (like running out of memory).
 68
 69</td></tr><tr><td> (exn match) </td><td>
 70
 71Signaled on errors raised by failed matches (see the section on {{match}}).
 72
 73</td></tr><tr><td> (exn syntax) </td><td>
 74
 75Signaled on syntax errors.
 76
 77</td></tr>
 78
 79</table>
 80
 81=== Notes
 82
 83* All error-exceptions (of the kind {{exn}}) are non-continuable.
 84
 85* Error-exceptions of the {{exn}} kind have additional {{arguments}} and
 86{{location}} properties that contain the arguments passed to the
 87exception-handler and the name of the procedure where the error occurred (if
 88available).
 89
 90* Within the interpreter (csi), a user-interrupt ({{signal/int}}) signals an
 91exception of the kind {{user-interrupt}}.
 92
 93* The procedure {{condition-property-accessor}} accepts an optional third
 94argument. If the condition does not have a value for the desired property and
 95if the optional argument is given, no error is signaled and the accessor
 96returns the third argument.
 97
 98* On platforms that support the {{sigprocmask(3)}} POSIX API function,
 99the signals {{SIGSEGV}}, {{SIGFPE}}, {{SIGBUS}} and {{SIGILL}} will be
100caught and trigger an exception instead of aborting the process, if
101possible. If the unwinding and handling of the signal raises one of
102these signals once again, the process will abort with an error
103message.
104
105* New in CHICKEN 5.4.0: condition objects produced by procedures that
106change errno have an {{errno}} property.  To access it, use
107{{(get-condition-property <the-condition-object> 'exn 'errno)}}.
108
109=== Additional API
110
111==== condition-case
112
113<macro>(condition-case EXPRESSION CLAUSE ...)</macro>
114
115Evaluates {{EXPRESSION}} and handles any exceptions that are covered by
116{{CLAUSE ...}}, where {{CLAUSE}} should be of the following form:
117
118  CLAUSE = ([VARIABLE] (KIND ...) BODY ...)
119
120If provided, {{VARIABLE}} will be bound to the signaled exception
121object. {{BODY ...}} is executed when the exception is a property-
122or composite condition with the kinds given {{KIND ...}} (unevaluated).
123If no clause applies, the exception is re-signaled in the same dynamic
124context as the {{condition-case}} form.
125
126<enscript highlight=scheme>
127(define (check thunk)
128  (condition-case (thunk)
129    [(exn file) (print "file error")]
130    [(exn) (print "other error")]
131    [var () (print "something else")] ) )
132
133(check (lambda () (open-input-file "")))   ; -> "file error"
134(check (lambda () some-unbound-variable))  ; -> "othererror"
135(check (lambda () (signal 99)))            ; -> "something else"
136
137(condition-case some-unbound-variable
138  ((exn file) (print "ignored")) )      ; -> signals error
139</enscript>
140
141==== get-condition-property
142
143<procedure>(get-condition-property CONDITION KIND PROPERTY [DEFAULT])</procedure>
144
145A slightly more convenient condition property accessor, equivalent to
146
147 ((condition-property-accessor KIND PROPERTY [DEFAULT]) CONDITION)
148
149==== condition
150
151<procedure>(condition LST1 LST2 ...)</procedure>
152
153This is a more convenient constructor for conditions.  Each of
154{{LST1}}, {{LST2}} etc is a list of the following form:
155
156  (KIND PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...)
157
158In other words, the following:
159
160  (signal (condition '(exn location foo message "hi") '(file bar 1)))
161
162is equivalent to the SRFI-12 code:
163
164  (signal (make-composite-condition
165            (make-property-condition 'exn 'location 'foo 'message "hi")
166            (make-property-condition 'file 'bar 2)))
167
168
169==== condition->list
170
171<procedure>(condition->list CONDITION)</procedure>
172
173This procedure converts a condition object into a list holding all the
174conditions that are represented by the ''CONDITION'' object.  It is
175formatted as follows:
176
177 ((KIND1 PROPERTY1 VALUE1 PROPERTY2 VALUE2 ...) (KIND2 ... ) ... )
178
179There is no guaranteed order within the list.
180
181
182==== print-error-message
183
184<procedure>(print-error-message EXN [PORT [HEADER]])</procedure>
185
186Prints an appropriate error message to {{PORT}} (which defaults to the
187value of {{(current-output-port)}} for the object {{EXN}}. {{EXN}} may
188be a condition, a string or any other object. The output is prefixed
189by the {{HEADER}}, which defaults to {{"Error:"}}.
190
191
192
193== SRFI-12 specification
194
195A Scheme implementation ("the system") raises an exception whenever an
196error is to be signaled or whenever the system determines that evaluation
197cannot proceed in a manner consistent with the semantics of Scheme. A
198program may also explicitly raise an exception.
199
200Whenever the system raises an exception, it invokes the current exception
201handler with a condition object (encapsulating information about the
202exception) as its only argument. Any procedure accepting one argument
203may serve as an exception handler. When a program explicitly raises an
204exception, it may supply any object to the exception handler.
205
206An exception is either continuable or non-continuable. When the current
207exception handler is invoked for a continuable exception, the continuation
208uses the handler's result(s) in an exception-specific way to continue.
209When an exception handler is invoked for a non-continuable exception,
210the continuation raises a non-continuable exception indicating that the
211exception handler returned.  On CHICKEN, system error exceptions
212(of kind {{exn}}) are non-continuable.
213
214=== Exception Handlers
215
216==== current-exception-handler
217
218<parameter>(current-exception-handler [PROCEDURE])</parameter><br>
219
220Sets or returns the current exception handler, a procedure of one
221argument, the exception object.
222
223==== with-exception-handler
224
225<procedure>(with-exception-handler handler thunk)</procedure><br>
226
227Returns the result(s) of invoking ''thunk''. The ''handler'' procedure
228is installed as the current exception handler in the dynamic context of
229invoking ''thunk''.
230
231Example:
232
233<enscript highlight=scheme>
234(call-with-current-continuation
235 (lambda (k)
236  (with-exception-handler (lambda (x) (k '()))
237                          (lambda () (car '())))))
238;=> '()
239</enscript>
240
241Note that the handler procedure must somehow return non-locally out of
242the dynamic extent of the {{with-exception-handler}} form, because
243returning normally will signal yet another exception and thus result
244in non-termination.
245
246==== handle-exceptions
247
248<macro>(handle-exceptions var handle-expr expr1 expr2 ...)</macro><br>
249
250Evaluates the body expressions ''expr1'', ''expr2'', ... in sequence with
251an exception handler constructed from ''var'' and ''handle-expr''. Assuming
252no exception is raised, the result(s) of the last body expression is(are)
253the result(s) of the {{handle-exceptions}} expression.
254
255The exception handler created by {{handle-exceptions}} restores the dynamic
256context (continuation, exception handler, etc.) of the {{handle-exceptions}}
257expression, and then evaluates ''handle-expr'' with ''var'' bound to the
258value provided to the handler.
259
260Examples:
261
262<enscript highlight=scheme>
263(handle-exceptions exn
264		   (begin
265		     (display "Went wrong")
266		     (newline))
267 (car '()))
268; displays "Went wrong"
269 
270(handle-exceptions exn 
271		   (cond
272		    ((eq? exn 'one) 1)
273		     (else (abort exn)))
274  (case (random 3)
275   [(0) 'zero]
276   [(1) (abort 'one)]
277   [else (abort "Something else")]))
278;=> 'zero, 1, or (abort "Something else")
279</enscript>
280
281=== Raising Exceptions
282
283==== abort
284
285<procedure>(abort obj)</procedure><br>
286
287Raises a non-continuable exception represented by ''obj''. The {{abort}}
288procedure can be implemented as follows:
289
290<enscript highlight=scheme>
291(define (abort obj)
292  ((current-exception-handler) obj)
293  (abort (make-property-condition
294	   'exn
295	   'message
296	   "Exception handler returned")))
297</enscript>
298
299The {{abort}} procedure does not ensure that its argument is a condition.
300If its argument is a condition, {{abort}} does not ensure that the condition
301indicates a non-continuable exception.
302
303==== signal
304
305<procedure>(signal obj)</procedure><br>
306
307Raises a continuable exception represented by ''obj''. The {{signal}} procedure
308can be implemented as follows:
309
310<enscript highlight=scheme>
311(define (signal exn)
312 ((current-exception-handler) exn))
313</enscript>
314
315The {{signal}} procedure does not ensure that its argument is a condition.
316If its argument is a condition, {{signal}} does not ensure that the condition
317indicates a continuable exception.
318
319=== Condition Objects
320
321==== condition?
322
323<procedure>(condition? obj)</procedure><br>
324
325Returns #t if ''obj'' is a condition, otherwise returns #f. If any of
326the predicates listed in Section 3.2 of the R5RS is true of ''obj'', then
327{{condition?}} is false of ''obj''.
328
329Rationale: Any Scheme object may be passed to an exception handler. This
330would cause ambiguity if conditions were not disjoint from all of Scheme's
331standard types.
332
333==== make-property-condition
334
335<procedure>(make-property-condition kind-key prop-key value ...)</procedure><br>
336
337This procedure accepts any even number of arguments after ''kind-key'',
338which are regarded as a sequence of alternating ''prop-key'' and ''value''
339objects. Each ''prop-key'' is regarded as the name of a property, and
340each ''value'' is regarded as the value associated with the ''key'' that
341precedes it. Returns a ''kind-key'' condition that associates the given
342''prop-key''s with the given ''value''s.
343
344==== make-composite-condition
345
346<procedure>(make-composite-condition condition ...)</procedure><br>
347
348Returns a newly-allocated condition whose components correspond to the
349given ''condition''s. A predicate created by {{condition-predicate}} returns
350true for the new condition if and only if it returns true for one or more
351of its component conditions.
352
353==== condition-predicate
354
355<procedure>(condition-predicate kind-key)</procedure><br>
356
357Returns a predicate that can be called with any object as its argument.
358Given a condition that was created by {{make-property-condition}}, the
359predicate returns #t if and only if ''kind-key'' is EQV? to the kind key
360that was passed to {{make-property-condition}}. Given a composite condition
361created with {{make-composite-condition}}, the predicate returns #t if and only
362if the predicate returns #t for at least one of its components.
363
364==== condition-property-accessor
365
366<procedure>(condition-property-accessor kind-key prop-key [default])</procedure><br>
367
368Returns a procedure that can be called with any condition that satisfies
369{{(condition-predicate ''kind-key'')}}. Given a condition that was created
370by {{make-property-condition}} and ''kind-key'', the procedure returns the
371value that is associated with ''prop-key''. Given a composite condition
372created with {{make-composite-condition}}, the procedure returns the value that
373is associated with ''prop-key'' in one of the components that satisfies
374{{(condition-predicate ''kind-key'')}}.
375
376On CHICKEN, this procedure accepts an optional third argument
377DEFAULT. If the condition does not have a value for the desired
378property and if the optional argument is given, no error is signaled
379and the accessor returns the third argument.
380
381When the system raises an exception, the condition it passes to the
382exception handler includes the {{'exn}} kind with the following
383properties:
384
385; message : the error message
386; arguments: the arguments passed to the exception handler
387; location: the name of the procedure where the error occurred (if available)
388
389Thus, if ''exn'' is a condition representing a system exception,
390then
391
392<enscript highlight=scheme>
393 ((condition-property-accessor 'exn 'message) exn)
394</enscript>
395
396extracts the error message from ''exn''. Example:
397
398<enscript highlight=scheme>
399(handle-exceptions exn 
400		   (begin
401		     (display "Went wrong: ")
402		     (display
403		      ((condition-property-accessor 'exn 'message) exn))
404		     (newline))
405 (car '()))
406; displays something like "Went wrong: can't take car of nil"
407</enscript>
408
409=== More Examples
410
411<enscript highlight=scheme>
412(define (try-car v)
413 (let ((orig (current-exception-handler)))
414   (with-exception-handler
415    (lambda (exn)
416      (orig (make-composite-condition
417	     (make-property-condition
418	      'not-a-pair
419	      'value
420	      v)
421	     exn)))
422    (lambda () (car v)))))
423 
424(try-car '(1))
425;=> 1
426
427(handle-exceptions exn
428		   (if ((condition-predicate 'not-a-pair) exn)
429		       (begin
430			(display "Not a pair: ")
431			(display
432			 ((condition-property-accessor 'not-a-pair 'value) exn))
433			(newline))
434		       (abort exn))
435  (try-car 0))
436; displays "Not a pair: 0"
437
438(let* ((cs-key (list 'color-scheme))
439       (bg-key (list 'background))
440       (color-scheme? (condition-predicate cs-key))
441       (color-scheme-background 
442	(condition-property-accessor cs-key bg-key))
443       (condition1 (make-property-condition cs-key bg-key 'green))
444       (condition2 (make-property-condition cs-key bg-key 'blue))
445       (condition3 (make-composite-condition condition1 condition2)))
446  (and (color-scheme? condition1)
447       (color-scheme? condition2)
448       (color-scheme? condition3)
449       (color-scheme-background condition3)))
450; => 'green or 'blue
451</enscript>
452
453----
454Previous: [[Module (chicken blob)]]
455
456Next: [[Module (chicken continuation)]]
Trap